/**
 * Author(s): xuming.Wong <xuming.Wong@gmail.com>
 */
#include "TerrainObject.h"

#include "SceneObject.h"
#include "SpriteManager.h"
#include "TerrainManager.h"
#include "GameEngine.h"

namespace PQEngine
{
	TerrainObject* TerrainObject:: _head=NULL;
	TerrainObject* TerrainObject:: _current=NULL;
	TerrainObject::TerrainObjectList TerrainObject::_list;
	TerrainObject::TerrainList TerrainObject::_terrainList;

	Ogre::String getTerrainName(int slotX,int slotY)
	{
		Ogre::String name="Terrain_";
		name+=Ogre::StringConverter::toString(slotX);
		name+="_";
		name+=Ogre::StringConverter::toString(slotY);
		return name;
	}

	TerrainObject::TerrainObject(SceneObject* sceneObject,Ogre::Terrain* terrain,int slotX,int slotY)
		: GameObject(sceneObject,GAME_OBJECT_TERRAIN),
		_terrain(terrain),_slotX(slotX),_slotY(slotY),_heightData(0),_next(0),
		_selectedLayer(-1),_editMode(TERRAIN_EDIT_NONE)
	{
		Ogre::String name=getTerrainName(slotX,slotY);
		this->setName(name);

		_restitution = TerrainManager::TERRAIN_DEFAULT_RESTITUTION;
		_friction = TerrainManager::TERRAIN_DEFAULT_FRICTION;
		
		if(_head==NULL){
			_head=this;	
		}else{
			_current->setNext(this);
		}
		_current=this;

		int id=slotX+slotY*TerrainManager::TERRAIN_SLOT_MAX;
		_list.insert(TerrainObjectList::value_type(id,this));//slotX+slotY*TerrainManager::TERRAIN_SLOT_MAX
		_terrainList.insert(TerrainList::value_type(terrain,this));

		_terrainComponent=new TerrainComponent();
		_terrainComponent->attach(this);
	}

	TerrainComponent* TerrainObject::getTerrainComponent()
	{
		return _terrainComponent;
	}

	TerrainObject* TerrainObject::addTerrain(SceneObject* sceneObject,Ogre::Terrain* terrain,int slotX,int slotY)
	{
		TerrainObject* object=new TerrainObject(sceneObject,terrain,slotX,slotY);
		
		return object;
	}

	TerrainObject* TerrainObject::get(int slotX,int slotY)
	{
		int id=slotX+slotY*TerrainManager::TERRAIN_SLOT_MAX;

		TerrainObjectList::iterator it=_list.find(id);
		if(it!=_list.end()){
			return it->second;
		}
		return 0;
	}

	TerrainObject* TerrainObject::get(Ogre::Terrain* terrain)
	{
		if(!terrain){
			return 0;
		}

		TerrainList::iterator it=_terrainList.find(terrain);
		if(it!=_terrainList.end()){
			return it->second;
		}
		return 0;
	}

	void TerrainObject::selectObject(bool selected)
	{
		if(!selected){
			_editMode=TERRAIN_EDIT_NONE;
		}else{
			_editMode=TERRAIN_EDIT_HIGHT;
			
		}
		
		GameObject::selectObject(selected);
	}


	Ogre::Vector3 TerrainObject::getSlotPosition(int slotX,int slotY)
	{
		TerrainObject* object=get(slotX,slotY);
		if(object==NULL){
			return Ogre::Vector3();
		}
		return object->getWorldPosition();
	}

	void TerrainObject::addLayer(std::string textureName)
	{
		int layer=_layerTextureList.size();
		if(layer>=256){
			return;
		}


		_terrain->addLayer();
		_terrain->setLayerTextureName(layer,0,textureName);//texture already load into resource group?
		_terrain->setLayerWorldSize(layer,100);//
		
		_layerTextureList.push_back(textureName);
	}

	void TerrainObject::addLayer(int textureIndex)
	{
		int layer=_layerTextureList.size();
		if(layer>=256){
			return;
		}
		
		Ogre::String textureName=_sceneObject->getTerrainTextureName(textureIndex);
		
		_terrain->addLayer();
		_terrain->setLayerTextureName(layer,0,textureName);//texture already load into resource group?
		_terrain->setLayerWorldSize(layer,100);//
		
		_layerTextureList.push_back(textureName);

	}


	float* TerrainObject::getHeightData()
	{
		if(_terrain==NULL){
			return 0;
		}
		if(_heightData==NULL){
			_heightData = new float [TerrainManager::TERRAIN_SIZE*TerrainManager::TERRAIN_SIZE];
			for(int i=0;i<TerrainManager::TERRAIN_SIZE;i++){
				for(int j=0;j<TerrainManager::TERRAIN_SIZE;j++){
					float y=(float)i/(float)(TerrainManager::TERRAIN_SIZE-1);
					float x=(float)j/(float)(TerrainManager::TERRAIN_SIZE-1);
					_heightData[i*TerrainManager::TERRAIN_SIZE+j]=_terrain->getHeightAtTerrainPosition(x,y);
				}
			}
		}
		return _heightData;
	}
}
